package com.example.airobotsettings.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
public class JwtUtil {
    private static final String SECRET_KEY = "your-secret-key";
    private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 24小时
    private static final String TOKEN_BLACKLIST_PREFIX = "token:blacklist:";
    private static final String TOKEN_PREFIX = "token:user:";

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 生成token并存储到Redis
     * @param username 用户名
     * @return token字符串
     */
    public String generateToken(String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);

        String token = Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();

        // 将token存储到Redis，key为 token:user:username
        String tokenKey = TOKEN_PREFIX + username;
        redisTemplate.opsForValue().set(tokenKey, token, EXPIRATION_TIME, TimeUnit.MILLISECONDS);

        return token;
    }

    /**
     * 验证token
     * @param token token字符串
     * @return 用户名，如果token无效则返回null
     */
    public String validateToken(String token) {
        try {
            if (token.startsWith("Bearer ")){
                token = token.substring(7);
            }
            
            // 检查token是否在Redis黑名单中
            String blacklistKey = TOKEN_BLACKLIST_PREFIX + token;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(blacklistKey))) {
                return null;
            }

            // 解析token获取用户名
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
            
            String username = claims.getSubject();
            
            // 验证Redis中是否存在该用户的token
            String tokenKey = TOKEN_PREFIX + username;
            String storedToken = redisTemplate.opsForValue().get(tokenKey);
            
            // 如果Redis中的token与当前token不一致，说明用户在其他地方登录，当前token失效
            if (storedToken == null || !storedToken.equals(token)) {
                return null;
            }

            return username;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 使token失效（加入黑名单）
     * @param token token字符串
     */
    public void invalidateToken(String token) {
        if (token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        
        try {
            // 解析token获取用户名和过期时间
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
            
            String username = claims.getSubject();
            Date expiration = claims.getExpiration();
            Date now = new Date();
            
            // 计算token的剩余有效期
            long ttl = expiration.getTime() - now.getTime();
            
            if (ttl > 0) {
                // 将token加入Redis黑名单
                String blacklistKey = TOKEN_BLACKLIST_PREFIX + token;
                redisTemplate.opsForValue().set(blacklistKey, "1", ttl, TimeUnit.MILLISECONDS);
                
                // 删除用户token
                String tokenKey = TOKEN_PREFIX + username;
                redisTemplate.delete(tokenKey);
            }
        } catch (Exception e) {
            // token解析失败，说明token已经无效，不需要加入黑名单
        }
    }

    /**
     * 强制使用户所有token失效（用于修改密码等场景）
     * @param username 用户名
     */
    public void invalidateAllUserTokens(String username) {
        String tokenKey = TOKEN_PREFIX + username;
        String token = redisTemplate.opsForValue().get(tokenKey);
        
        if (token != null) {
            invalidateToken(token);
        }
    }

    /**
     * 清理过期的黑名单token
     * 注意：使用Redis后，不需要手动清理，因为Redis会自动处理过期数据
     */
    public void cleanBlacklist() {
        // Redis会自动处理过期数据，此方法可以保留但不需要实现
    }
}
